package jmine.tec.rpc.common.serialization.json;

import java.lang.reflect.InvocationTargetException;

import jmine.tec.json.JSON;
import jmine.tec.json.JSONObject;
import jmine.tec.json.JSONString;
import jmine.tec.rpc.RPCMessages;
import jmine.tec.rpc.common.RPCException;

import org.apache.commons.beanutils.ConstructorUtils;

import bancosys.tec.exception.LocalizedMessageHolder;

/**
 * Conversor de JSON para Java e vice-versa
 * 
 * @author lundberg
 */
public class JSONThrowableConverter extends AbstractJSONObjectConverter implements JSONConverterStrategy {

    private static final String BEAN_CLASS = "&class";

    private static final String MESSAGE = "&message";

    /**
     * {@inheritDoc}
     */
    public boolean matchesJava(Object object) {
        return object instanceof Throwable;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected JSON objectType() {
        return new JSONString("throwable");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected Object instantiate(JSONConversionContext context, JSON json) {
        try {
            return this.createException(context, json);
        } catch (Exception e) {
            throw new RPCException(RPCMessages.JSON_ERROR_CREATING_BEAN.create(), e);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void fillObject(JSONConversionContext context, JSON json, Object object) {
        // OK
    }

    /**
     * @param context context
     * @param json json
     * @return Object
     * @throws ClassNotFoundException ClassNotFoundException
     * @throws NoSuchMethodException NoSuchMethodException
     * @throws IllegalAccessException IllegalAccessException
     * @throws InvocationTargetException InvocationTargetException
     * @throws InstantiationException InstantiationException
     */
    private Object createException(JSONConversionContext context, JSON json) throws ClassNotFoundException, NoSuchMethodException,
            IllegalAccessException, InvocationTargetException, InstantiationException {
        Class objectClass = (Class) context.toJava(json.getProperty(BEAN_CLASS));
        String message = json.getProperty(MESSAGE).toString();
        try {
            return ConstructorUtils.invokeConstructor(objectClass, new Object[]{ message });
        } catch (NoSuchMethodException e) {
            LocalizedMessageHolder holder = RPCMessages.REMOTE_EXCEPTION_MESSAGE.create(message);
            return ConstructorUtils.invokeConstructor(objectClass, new Object[]{ holder });
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void fillJSON(JSONConversionContext context, Object object, JSONObject json) {
        json.setProperty(BEAN_CLASS, context.toJSON(object.getClass()));
        json.setProperty(MESSAGE, context.toJSON(((Throwable) object).getMessage()));
    }
}
